home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Ham Radio 2000 #2
/
Ham Radio 2000 - Volume 2.iso
/
HAMV2
/
TCP_IP
/
TNOS230S
/
DOMHDR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-08-18
|
13KB
|
539 lines
/* Domain header conversion routines
* Copyright 1991 Phil Karn, KA9Q
*
* Additional support for the Domain Name Server
* by Johan. K. Reinalda, WG7J,
* based on previous work by Gerard v.d. Grinten, PA0GRI
*/
#include "global.h"
#include "mbuf.h"
#include "domain.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: domhdr.c,v 1.14 1997/08/19 01:19:22 root Exp root $";
#endif
static int dn_expand (char *msg, char *eom, char *compressed, char *full, int fullen);
static char *getq (struct rr ** rrpp, char *msg, char *cp);
static char *ntohrr (struct rr ** rrpp, char *msg, char *cp);
#ifdef DSERVER
static char *dn_compress (char *cp, char *name);
static char *htonrr (struct rr * rr, char *buffer);
#endif
int
ntohdomain (dhdr, bpp)
register struct dhdr *dhdr;
struct mbuf **bpp;
{
int16 tmp, len;
register int16 i;
char *msg, *cp;
struct rr **rrpp;
len = len_p (*bpp);
msg = mallocw ((unsigned) len);
(void) pullup (bpp, (unsigned char *) msg, len);
memset ((char *) dhdr, 0, sizeof (*dhdr));
dhdr->id = get16 (&msg[0]);
tmp = get16 (&msg[2]);
if (tmp & 0x8000)
dhdr->qr = 1;
dhdr->opcode = (tmp >> 11) & 0xf;
if (tmp & 0x0400)
dhdr->aa = 1;
if (tmp & 0x0200)
dhdr->tc = 1;
if (tmp & 0x0100)
dhdr->rd = 1;
if (tmp & 0x0080)
dhdr->ra = 1;
dhdr->rcode = tmp & 0xf;
dhdr->qdcount = get16 (&msg[4]);
dhdr->ancount = get16 (&msg[6]);
dhdr->nscount = get16 (&msg[8]);
dhdr->arcount = get16 (&msg[10]);
/* Now parse the variable length sections */
cp = &msg[12];
/* Question section */
rrpp = &dhdr->questions;
for (i = 0; i < dhdr->qdcount; i++) {
if ((cp = getq (rrpp, msg, cp)) == NULLCHAR) {
free (msg);
return -1;
}
(*rrpp)->source = RR_QUESTION;
rrpp = &(*rrpp)->next;
}
*rrpp = NULLRR;
/* Answer section */
rrpp = &dhdr->answers;
for (i = 0; i < dhdr->ancount; i++) {
if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
free (msg);
return -1;
}
(*rrpp)->source = RR_ANSWER;
rrpp = &(*rrpp)->next;
}
*rrpp = NULLRR;
/* Name server (authority) section */
rrpp = &dhdr->authority;
for (i = 0; i < dhdr->nscount; i++) {
if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
free (msg);
return -1;
}
(*rrpp)->source = RR_AUTHORITY;
rrpp = &(*rrpp)->next;
}
*rrpp = NULLRR;
/* Additional section */
rrpp = &dhdr->additional;
for (i = 0; i < dhdr->arcount; i++) {
if ((cp = ntohrr (rrpp, msg, cp)) == NULLCHAR) {
free (msg);
return -1;
}
(*rrpp)->source = RR_ADDITIONAL;
rrpp = &(*rrpp)->next;
}
*rrpp = NULLRR;
free (msg);
return 0;
}
static char *
getq (rrpp, msg, cp)
struct rr **rrpp;
char *msg;
char *cp;
{
register struct rr *rrp;
int len;
char *name;
*rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
name = mallocw (512);
len = dn_expand (msg, NULLCHAR, cp, name, 512);
if (len == -1) {
free (name);
return NULLCHAR;
}
cp += len;
rrp->name = strdup (name);
rrp->type = get16 (cp);
cp += 2;
rrp->class = get16 (cp);
cp += 2;
rrp->ttl = 0;
rrp->rdlength = 0;
free (name);
return cp;
}
/* Read a resource record from a domain message into a host structure */
static char *
ntohrr (rrpp, msg, cp)
struct rr **rrpp; /* Where to allocate resource record structure */
char *msg; /* Pointer to beginning of domain message */
char *cp; /* Pointer to start of encoded RR record */
{
register struct rr *rrp;
int len;
char *name;
*rrpp = rrp = (struct rr *) callocw (1, sizeof (struct rr));
name = mallocw (512);
if ((len = dn_expand (msg, NULLCHAR, cp, name, 512)) == -1) {
free (name);
return NULLCHAR;
}
cp += len;
rrp->name = strdup (name);
rrp->type = get16 (cp);
cp += 2;
rrp->class = get16 (cp);
cp += 2;
rrp->ttl = (int32) get32 (cp);
cp += 4;
rrp->rdlength = get16 (cp);
cp += 2;
switch (rrp->type) {
case TYPE_A:
/* Just read the address directly into the structure */
rrp->rdata.addr = get32 (cp);
cp += 4;
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
/* These types all consist of a single domain name;
* convert it to ascii format
*/
len = dn_expand (msg, NULLCHAR, cp, name, 512);
if (len == -1) {
free (name);
return NULLCHAR;
}
rrp->rdata.name = strdup (name);
rrp->rdlength = (int16) strlen (name);
cp += len;
break;
case TYPE_HINFO:
len = *cp++;
rrp->rdata.hinfo.cpu = mallocw ((unsigned) len + 1);
memcpy (rrp->rdata.hinfo.cpu, cp, (size_t) len);
rrp->rdata.hinfo.cpu[len] = '\0';
cp += len;
len = *cp++;
rrp->rdata.hinfo.os = mallocw ((unsigned) len + 1);
memcpy (rrp->rdata.hinfo.os, cp, (size_t) len);
rrp->rdata.hinfo.os[len] = '\0';
cp += len;
break;
case TYPE_MX:
rrp->rdata.mx.pref = get16 (cp);
cp += 2;
/* Get domain name of exchanger */
len = dn_expand (msg, NULLCHAR, cp, name, 512);
if (len == -1) {
free (name);
return NULLCHAR;
}
rrp->rdata.mx.exch = strdup (name);
cp += len;
break;
case TYPE_SOA:
/* Get domain name of name server */
len = dn_expand (msg, NULLCHAR, cp, name, 512);
if (len == -1) {
free (name);
return NULLCHAR;
}
rrp->rdata.soa.mname = strdup (name);
cp += len;
/* Get domain name of responsible person */
len = dn_expand (msg, NULLCHAR, cp, name, 512);
if (len == -1) {
free (name);
return NULLCHAR;
}
rrp->rdata.soa.rname = strdup (name);
cp += len;
rrp->rdata.soa.serial = (int32) get32 (cp);
cp += 4;
rrp->rdata.soa.refresh = (int32) get32 (cp);
cp += 4;
rrp->rdata.soa.retry = (int32) get32 (cp);
cp += 4;
rrp->rdata.soa.expire = (int32) get32 (cp);
cp += 4;
rrp->rdata.soa.minimum = (int32) get32 (cp);
cp += 4;
break;
case TYPE_TXT:
/* Just stash */
rrp->rdata.data = mallocw ((unsigned) rrp->rdlength);
memcpy (rrp->rdata.data, cp, (size_t) rrp->rdlength);
cp += rrp->rdlength;
break;
default:
/* Ignore */
cp += rrp->rdlength;
break;
}
free (name);
return cp;
}
/* Convert a compressed domain name to the human-readable form */
static int
dn_expand (msg, eom, compressed, full, fullen)
char *msg; /* Complete domain message */
char *eom OPTIONAL;
char *compressed; /* Pointer to compressed name */
char *full; /* Pointer to result buffer */
int fullen; /* Length of same */
{
unsigned int slen; /* Length of current segment */
register char *cp;
int clen = 0; /* Total length of compressed name */
int indirect = 0; /* Set if indirection encountered */
int nseg = 0; /* Total number of segments in name */
cp = compressed;
for (;;) {
slen = uchar (*cp++); /* Length of this segment */
if (!indirect)
clen++;
if ((slen & 0xc0) == 0xc0) {
if (!indirect)
clen++;
indirect = 1;
/* Follow indirection */
cp = &msg[((slen & 0x3f) << 8) + uchar (*cp)];
slen = uchar (*cp++);
}
if (slen == 0) /* zero length == all done */
break;
fullen -= (int) (slen + 1);
if (fullen < 0)
return -1;
if (!indirect)
clen += (int) slen;
while (slen-- != 0)
*full++ = *cp++;
*full++ = '.';
nseg++;
}
if (nseg == 0) {
/* Root name; represent as single dot */
*full++ = '.';
fullen--;
}
*full++ = '\0';
fullen--;
return clen; /* Length of compressed message */
}
#ifdef DSERVER
/* Most of this code is based on the DNS server in PA0GRI's 910828
* Ported to the current NOS code by Johan. K. Reinalda, WG7J
* for version and bug/feature info, see domain.c
*/
static char *
dn_compress (cp, name)
char *cp, *name;
{
int len, dlen;
char *cp1;
char *nametmp;
if (!name)
return cp;
dlen = (int) strlen (name);
for (;;) {
/* Look for next dot */
cp1 = strchr (name, '.');
if (cp1 != NULLCHAR)
len = cp1 - name; /* More to come */
else
len = dlen; /* Last component */
*cp++ = (char) len; /* Write length of component */
if (len == 0)
return cp;
/* Copy component up to (but not including) dot */
nametmp = name;
strncpy (cp, nametmp, (size_t) len);
cp += len;
if (cp1 == NULLCHAR) {
*cp++ = 0; /* Last one; write null and finish */
return cp;
}
name += len + 1;
dlen -= len + 1;
}
}
/* Translate a resource record from host format to network format */
static char *
htonrr (rr, buffer)
struct rr *rr;
char *buffer;
{
struct rr *rrp;
unsigned char *cp, *p;
int i, len;
cp = (unsigned char *) buffer;
for (rrp = rr; rrp != NULLRR; rrp = rrp->next) {
#ifdef notdef
i = strlen (rrp->name);
if (rrp->name[i - 1] != '.'
&& rrp->origin != NULLCHAR) {
p = mallocw (i + strlen (rrp->origin) + 2);
sprintf (p, "%s.%s", rrp->name, rrp->origin);
cp = dn_compress (cp, p);
free (p);
} else
#endif
cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
cp = put16 (cp, rrp->type);
cp = put16 (cp, rrp->class);
cp = put32 (cp, (uint32) rrp->ttl);
#ifdef notdef
/* The length doesn't seem to be right for all types ! */
cp = put16 (cp, rrp->rdlength);
#endif
p = cp; /* This is where the length goes ! */
cp += 2; /* Save the space for lenght field */
switch (rrp->type) {
case TYPE_A:
cp = put32 (cp, rrp->rdata.addr);
break;
case TYPE_SOA:
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.mname);
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.soa.rname);
cp = put32 (cp, (uint32) rrp->rdata.soa.serial);
cp = put32 (cp, (uint32) rrp->rdata.soa.refresh);
cp = put32 (cp, (uint32) rrp->rdata.soa.retry);
cp = put32 (cp, (uint32) rrp->rdata.soa.expire);
cp = put32 (cp, (uint32) rrp->rdata.soa.minimum);
break;
case TYPE_HINFO:
len = (int) strlen (rrp->rdata.hinfo.cpu);
*cp++ = uchar(len);
strncpy ((char *) cp, rrp->rdata.hinfo.cpu, (size_t) len);
cp += len;
len = (int) strlen (rrp->rdata.hinfo.os);
*cp++ = uchar(len);
strncpy ((char *) cp, rrp->rdata.hinfo.os, (size_t) len);
cp += len;
break;
case TYPE_MX:
cp = put16 (cp, rrp->rdata.mx.pref);
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.mx.exch);
break;
case TYPE_CNAME:
case TYPE_MB:
case TYPE_MG:
case TYPE_MR:
case TYPE_NS:
case TYPE_PTR:
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
break;
case TYPE_MINFO: /* Unsupported type */
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.rmailbx);
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.minfo.emailbx);
/* fall through */
case TYPE_MD: /* Unsupported type */
case TYPE_MF: /* Unsupported type */
case TYPE_NULL:/* Unsupported type */
case TYPE_WKS: /* Unsupported type */
cp = (unsigned char *) dn_compress ((char *) cp, rrp->rdata.data);
break;
case TYPE_TXT:
default:
cp = put16 (cp, rrp->rdlength);
for (i = 0; i < rrp->rdlength; i++)
*cp++ = uchar(rrp->rdata.data[i]);
break;
}
/* Calculate the lenght of the RR */
len = cp - p - 2;
(void) put16 (p, (int16) len); /* and set it */
}
return (char *) cp;
}
int
htondomain (dhdr, buffer, buflen)
struct dhdr *dhdr;
char *buffer; /* Area for query */
int16 buflen OPTIONAL; /* Length of same */
{
unsigned char *cp;
struct rr *rrp;
int16 parameter;
int i, count;
int done = 0;
cp = (unsigned char *) buffer;
cp = put16 (cp, dhdr->id);
if (dhdr->qr)
parameter = 0x8000;
else
parameter = 0;
parameter |= (dhdr->opcode & 0x0f) << 11;
if (dhdr->aa)
parameter |= DOM_AUTHORITY;
if (dhdr->tc)
parameter |= DOM_TRUNC;
if (dhdr->rd)
parameter |= DOM_DORECURSE;
if (dhdr->ra)
parameter |= DOM_CANRECURSE;
parameter |= (dhdr->rcode & 0x0f);
cp = put16 (cp, parameter);
cp = put16 (cp, dhdr->qdcount);
cp = put16 (cp, dhdr->ancount);
cp = put16 (cp, dhdr->nscount);
cp = put16 (cp, dhdr->arcount);
if ((count = dhdr->qdcount) > 0) {
rrp = dhdr->questions;
for (i = 0; i < count; i++) {
cp = (unsigned char *) dn_compress ((char *) cp, rrp->name);
cp = put16 (cp, rrp->type);
cp = put16 (cp, rrp->class);
rrp = rrp->next;
}
}
if (((char *) cp - buffer) > buflen)
done = 1;
if (!done && (count = dhdr->ancount) > 0) {
rrp = dhdr->answers;
for (i = 0; i < count; i++) {
cp = (unsigned char *) htonrr (rrp, (char *) cp);
if (((char *) cp - buffer) > buflen) {
done = 1;
break;
}
rrp = rrp->next;
}
}
if (!done && (count = dhdr->nscount) > 0) {
rrp = dhdr->authority;
for (i = 0; i < count; i++) {
cp = (unsigned char *) htonrr (rrp, (char *) cp);
if (((char *) cp - buffer) > buflen) {
done = 1;
break;
}
rrp = rrp->next;
}
}
if (!done && (count = dhdr->arcount) > 0) {
rrp = dhdr->additional;
for (i = 0; i < count; i++) {
cp = (unsigned char *) htonrr (rrp, (char *) cp);
if (((char *) cp - buffer) > buflen) {
done = 1;
break;
}
rrp = rrp->next;
}
}
return ((char *) cp - buffer);
}
#endif /* DSERVER */